﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;
using System.IO;
using Microsoft.Xna.Framework.Content;

namespace ProjectCastamere
{
    /// <summary>
    /// A singleton audio class. Manages all audio playback for all cues
    /// </summary>
    public class AudioManager : GameComponent
    {
        // The singleton for this type
        private static AudioManager audioManager = null;

        // The audio engine used to play all sound cues
        private AudioEngine audioEngine;

        // The soundbank that contains all cues
        private SoundBank soundBank;

        // The wavebank with all wave files for this game
        private WaveBank waveBank;

        // a private sound cue
        private Cue cue;

        // for 3D sounds
        private AudioEmitter emitter = new AudioEmitter();
        private AudioListener listener = new AudioListener();

        private float angle = 0;
        private float distance = 5;

        // Private constructor, constructs the manager for audio playback of all cues
        private AudioManager(Game game, string settingsFile, string waveBankFile, string soundBankFile)
            : base(game)
        {
            try
            {
                audioEngine = new AudioEngine(settingsFile);
                waveBank = new WaveBank(audioEngine, waveBankFile);
                soundBank = new SoundBank(audioEngine, soundBankFile);
            }
            catch (NoAudioHardwareException)
            {
                // Fail discretely....
                audioEngine = null;
                waveBank = null;
                soundBank = null;
            }
        }

        // Initialise the static audiomanager functionality
        public static void Initalise(Game game, string settingsFile, string waveBankFile, string soundBankFile)
        {
            // call the private constructor
            audioManager = new AudioManager(game, settingsFile, waveBankFile, soundBankFile);

            // if the game isnt null
            if (game != null)
            {
                // add the audio manager to the components list
                game.Components.Add(audioManager);
            }
        }

        /// <summary>
        /// Plays a 2D sound effect
        /// </summary>
        /// <param name="name">The name of the sound effect</param>
        public static void Play2DSoundEffect(string name)
        {
            audioManager.cue = audioManager.soundBank.GetCue(name);
            audioManager.cue.Play();
        }

        /// <summary>
        /// Plays a song
        /// </summary>
        /// <param name="name">The name of the song</param>
        public static void PlayMusic(string name)
        {
            audioManager.cue = audioManager.soundBank.GetCue(name);
            audioManager.cue.Play();
        }

        /// <summary>
        /// Plays a 3D sound effect, given the listener position and the emitter position
        /// other stuff can be manipulated if needed
        /// </summary>
        /// <param name="name"></param>
        /// <param name="listenerPosition"></param>
        /// <param name="emitterPosition"></param>
        public static void Play3DSoundEffect(string name, Vector3 listenerPosition, Vector3 emitterPosition)
        {
            audioManager.listener.Position = listenerPosition;
            audioManager.emitter.Position = emitterPosition;
            audioManager.cue.Apply3D(audioManager.listener, audioManager.emitter);
            audioManager.cue.Play();
        }

        // update the audio manager, mainly the engine
        public override void Update(GameTime gameTime)
        {
            // update the audio engine
            if (audioEngine != null)
            {
                audioEngine.Update();
            }
            base.Update(gameTime);
        }

        // dispose safely, and clean up 
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    if (soundBank != null)
                    {
                        soundBank.Dispose();
                        soundBank = null;
                    }
                    if (waveBank != null)
                    {
                        waveBank.Dispose();
                        waveBank = null;
                    }
                    if (audioEngine != null)
                    {
                        audioEngine.Dispose();
                        audioEngine = null;
                    }
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }
    }
}
